home *** CD-ROM | disk | FTP | other *** search
- #
- /*
- ** This is intended as a tutorial example of an Equel program.
- ** You should be familiar with both C and Quel before going
- ** through the examples. The program may be run to see how the
- ** examples actually work. To compile and run this program you
- ** should run the following shell commands:
- **
- ** equel equeltut.q
- ** cc equeltut.c -lq
- ** a.out
- **
- ** The first command invokes the Equel pre-processor which in-
- ** serts code to send queries to INGRES. The output is left in
- ** the file "equeltut.c" in this case. In general, the pre-
- ** processor is invoked as:
- **
- ** equel [-d] [-f] [-r] file1.q [file2.q ...]
- **
- ** The output is left in "file1.c", etc. The -d flag tells Equel
- ** to leave line number information in the file so that run time
- ** errors can be associated with the proper query.
- **
- ** It is possible to use the C-preprocessor to include files with
- ** Equel statements and/or declarations in it if these files have
- ** names ending in ".q.h". Such files will be processed by equel,
- ** and a C version left in the file ending in ".c.h", which will
- ** be #included by the C pre-processor. Files which are #included
- ** but whose names do not end in ".q.h" will be ignored by Equel.
- */
-
-
- /*
- ** Equel uses the same syntax as Quel in almost all cases. There
- ** are a few differences between Equel and Quel and also some
- ** subtleties in interfaceing Quel and C constructs. Some impor-
- ** tant points are:
- **
- ** C-variables declared to Equel are used as variables
- ** throughout Equel statements, except inside strings or when preceded
- ** by the non-referencing operator '#'. In particular, be care-
- ** ful with variable names which are the same as domain names.
- **
- ** All strings passed to C-variables from INGRES will be
- ** null terminated. This will make them one byte longer than
- ** they were in the relation, so you must declare character arrays
- ** to be one byte longer than the domain from which the data will
- ** come.
- **
- ** Retrieve statements with no result relation have a dif-
- ** ferent interpretation in Equel than in Quel. There will be
- ** many examples of this.
- */
-
-
-
-
-
- /*
- ** First some of the queries found in "A Tutorial on INGRES" are
- ** mapped into Equel so that the similarities and differences
- ** between the two modes of accessing INGRES can be seen.
- */
-
-
-
-
- /*
- ** We start by declaring some variables that will be needed for
- ** the interaction. Note that the variables are global to Equel,
- ** that is the declarations are in effect for the entire file.
- */
-
- ## char pname[21]; /*
- ** Pname is dimensioned to hold one more
- ** character than the pname field of the
- ** parts relation. We will need the ex-
- ** tra character so that Equel will have
- ** enough space to null terminate the
- ** string. More on this later.
- ** We must use the non-referencing
- ** operator when using "pname" as a
- ** field name, as the field has the same
- ** name as tha variable and equel will
- ** assume we mean the variable if we just
- ** write "pname."
- */
-
- ## char col[9]; /*
- ** This will be used to hold color attri-
- ** butes from the parts relation. It is
- ** named "col" insted of "color" so that
- ** the term "p.color" does not contain a
- ** variable reference, and may be used
- ** without the non-referencing operator.
- */
-
- main(argc, argv)
- int argc;
- char *argv[];
-
- {
-
- /*
- ** We start the interaction with INGRES using data base
- ** demo.
- */
-
-
- ## ingres "-i210" demo
-
- /*
- ** Up to 9 arguments may be specified to the INGRES call.
- ** Here we have modified the integer output format.
- ** Flags must be in quotes so that the plus or minus are
- ** not parsed incorrectly.
- */
-
-
-
- /*
- ** As in the INGRES tutorial, we may print the parts rela-
- ** tion:
- */
-
- ## print parts
-
- /*
- ** Note that this identical to the Quel statement except
- ** that the line is tagged with the "##" telling the Equ-
- ** el pre-processor to translate this line into standard
- ** C
- */
-
- /*
- ** The next section of code is intended to parallel the
- ** third query in the Tutorial [page 4]
- */
-
- ## range of p is parts /*
- ** This is identical to the Quel
- ** syntax. Note also the use of
- ** a comment in an Equel state-
- ** ment
- */
-
-
- /*
- ** Note that the first pname is assumed to refer to the vari-
- ** able "pname", while the second pname is assumed to be a
- ** constant name (as opposed to the value of the vari-
- ** able "pname") because of the non-referencing opera-
- ** tor.
- */
- ## retrieve (pname = p.#pname)
- ## {
- /*
- ** Everything inside the braces is repeated for
- ** each tuple that is retrieved.
- */
-
- printf("%s\n", pname);
-
- /*
- ** pname is a properly terminated C string. Equ-
- ** el null terminates ALL strings which are
- ** passed from INGRES. Strings will be of length
- ** one more than the width of the attribute. It
- ** is assumed that the user has provided enough
- ** room!!
- */
- ## }
-
-
-
- /*
- ** Now we will retrieve the colors and names of the parts
- ** We will skip the error in the Tutorial and simply note
- ** that the Equel interpreter would catch the error
- ** presented on page 4:
- ** ## retrieve pname = p.#pname, col = p.color
- ** with the message:
- ** IS = '=' : line 7, syntax error
- ** which is almost as helpful as the Quel message.
- */
-
-
-
-
- ## retrieve (pname = p.#pname, col = p.color)
- ## /*
- ** The name "col" was used for the variable name
- ** insted of "color". The latter would be treat-
- ** ed as a variable in the phrase "p.color" and
- ** INGRES would see "p." followed by the value
- ** color had at runtime.
- **
- ** The comment in this situation must start on a
- ** line with a "##" since Equel will look for the
- ** "## {" to be contiguous with the retrieve.
- ** The same holds for blank lines, they must begin
- ** with a "##" if they come before the "## {".
- */
- ## {
- printf("The color of the %s is %s\n", pname,col);
- ## }
-
- /*
- ** The ##{ and ##} are needed, even if you wish to repeat
- ** only one line of C-code inside the retrieve.
- */
-
- /*
- ** To retrieve and print the parts which are gray we may
- ** write:
- */
-
- printf("The following parts are gray:\n");
- ## retrieve (pname = p.#pname)
- ## where p.color = "gray"
- ## {
- printf("\t%s\n", pname);
- ## }
-
-
- /*
- ** The above query is similar to the query on page 5 of
- ** the Tutorial.
- */
-
-
- /*
- ** In Equel there is no notion of a "query buffer" as in
- ** the INGRES Terminal Monitor. If we want to do the
- ** query on page 6 of the Tutorial we must completely
- ** specify the query (except for the range statements):
- */
-
- ## retrieve (pname = p.#pname, col = p.color)
- ## where p.color = "gray"
- ## or p.color = "pink"
- ## {
- printf("The color of the %s is %s\n", pname, col);
- ## }
-
-
-
- /*
- ** We will now leave the Tutorial behind and use some of
- ** features particular to Equel.
- */
-
-
- example1();
-
- /*
- ** Next we have an interactive example...
- */
-
- raise();
-
- /*
- ** Next an example of "parametrized" Equel statements
- */
-
- param_ex();
- }
-
-
- /*
- ** Suppose we want to bring parts of a relation into core for
- ** some number crunching which would be difficult in INGRES.
- **
- ** This example brings elements of the supply relation into an
- ** array of structures.
- */
- # define MAXDATA 20
-
-
-
-
- /*
- ** This defines the fields "pnum", "snum", and "quan" to Equel.
- */
- ## struct supply
- ## {
- ## int pnum, snum;
- ## int quan;
- ## };
-
- /*
- ** The ##{ and ##} at the start and end of the example1() func-
- ** tion indicate the scope of variables declared within them.
- ** Therefore data is considered by Equel to be local to exam-
- ** ple1. Any free block (a ##{...##} not immeadiately after a
- ** ##retrieve without a result relation [an into]) makes vari-
- ** ables declared within it be local (there is, however, only
- ** one level of locality; i.e. either a variable is global to
- ** the file, or it is local to the outermost enclosing free
- ** block.
- */
-
- example1()
- ## {
-
- ## struct supply data [MAXDATA + 1];
- register int i;
-
- i = 0;
-
- ## range of s is supply
-
- /*
- ** The structure field names are known to be structure
- ** fields beacuse they were declared as such, and follow
- ** the structure variable "data". On the right side of
- ** the equals sign (=) they are not in the position of
- ** structure fields so are assumed to be domain names,
- ** although the non-referencing operator could be used
- ** here any way for clarity.
- */
-
- ## retrieve (data [i].pnum = s.pnum,
- ## data [i].snum = s.snum,
- ## data [i].quan = s.quan)
- ## where s.shipdate <= "76-12-10"
- ## {
- printf("supplier #%d, supplies %d of part %d.\n",
- data [i].snum, data [i].quan, data [i].pnum);
- if (i++ >= MAXDATA - 1)
- {
- printf("Too much data!\n");
- break;
- /*
- ** The break is legal because the re-
- ** trieve is converted into a "while"
- ** statement. Break is the only accept-
- ** able way to get out of a retrieve due
- ** to an user detected error. There is
- ** code after the "while" to flush out
- ** the data sent by INGRES which was not
- ** used by the Equel process.
- */
- }
-
- ## }
- ## }
-
-
-
-
-
-
-
- /*
- ** The routine provides an interactive secession for updating
- ** salaries. There are other ways of accomplishing this interac-
- ** tion but this mode brings out some of the possible pitfalls.
- */
-
- raise()
- ## {
- int flag;
- int per;
- ## char percent[10];
- ## char rname[21];
- ## char ename[21];
- ## int sal;
- ## char domain[20];
- ## char info[255];
- extern *IIinterrupt, reset();
-
- ## range of e is employee
-
- /*
- ** Since the range statement will be in effect as long as
- ** INGRES is running we declare it at the top of the
- ** loop rather than each time through the loop.
- */
-
-
-
- /*
- ** Before entering the loop we arrange to continue pro-
- ** cessing after an interrupt from the user. It is im-
- ** perative that we do not catch the signal at this point
- ** since INGRES will catch the signal and try to syn-
- ** chronize with the Equel process. When the Equel pro-
- ** cess has been synchronized it will call (*IIinter-
- ** rupt)().
- */
-
- #if 0
- IIinterrupt = reset;
- setexit();
- #endif
- loop:
- printf("Please enter employee's name\n");
-
- if (eread(ename))
- return (0);
-
- if (ename[0] == '?' && ename[1] == '\0')
- ## print employee
- else
- {
- flag = 0;
-
- /*
- ** In this interaction we do three queries and
- ** let INGRES do the arithmetic. The name is re-
- ** trieved into rname since ename may contain
- ** pattern matching characters and more than one
- ** name may be retrieved. For example "Ross*"
- ** may be entered and both Stanley and Stuart
- ** will get raises.
- */
-
- ## retrieve (rname = e.name, sal = e.salary)
- ## where e.name = ename
- ## {
- printf("The current salary of %s is %d\n",
- rname, sal);
- flag = 1;
- ## }
-
- if (!flag)
- {
- printf("No such employee\n");
- goto loop;
- }
- printf("Enter percent increase=");
- if (eread(percent))
- goto loop;
-
-
- /*
- ** There is no facility in Equel to examine,
- ** modify and then put back a tuple. The replace
- ** must contain the qualification since there is
- ** no connection between the previous retrieve
- ** and the replace.
- */
- ## replace e (salary = e.salary + float8(percent)/100. * e.salary)
- ## where e.name = ename
-
-
- per = atoi(percent);
-
- ## retrieve (rname = e.name, sal = e.salary)
- ## where e.name = ename
- ## {
- printf("With that ");
- if (per < 5)
- printf("piddly");
- else if (per < 10)
- printf("modest");
- else if (per < 30)
- printf("inflation fighting");
- else
- printf("tremendous");
- printf(" raise, %s now makes $%d\n",rname,sal);
- ## }
-
-
- printf("Do you want any other information about %s?\n"
- , ename);
-
- if (eread(domain) || domain[0] == 'n' )
- goto loop;
-
- printf("Enter domain: ");
-
- if (eread(domain))
- goto loop;
-
- /*
- ** If the user responds with a '?' then show him
- ** all possible domains by printing out the at-
- ** tributes of that relation from the tuple in
- ** the "attribute" relation.
- */
-
- if (domain[0] == '?' && domain[1] == '\0')
- {
-
- ## range of a is attribute
-
- ## retrieve(domain = a.attname)
- ## where a.attrelid = "employee"
- ## {
- printf("\t%s\n", domain);
- ## }
- printf("Enter domain: ");
-
- if (eread(domain))
- goto loop;
- }
-
-
- /*
- ** Here we use a C-variable as a domain name.
- ** The value of the variable is passed to INGRES
- ** and interpreted as part of the query.
- */
-
-
-
- /*
- ** The ascii funciton is used because the type of
- ** the domain is not known. Ascii applied to a
- ** character domain does nothing.
- */
- ## retrieve (rname = e.name, info = ascii(e.domain))
- ## where e.name = ename
- ## {
-
- printf("%s\t%s = %s\n", rname, domain, info);
- ## }
-
- }
- goto loop;
- }
-
- /*
- ** This routine shows the use of parametrized equel statements.
- ** These are equel statements where the target list is undeter-
- ** mined until run-time. In this way a variable number of
- ** domains, or variable types may be used in the same Equel
- ** statements.
- */
-
- param_ex()
- {
- char name [25]; /*
- ** Variables used in the
- ** target list of a
- ** parametrized state-
- ** ment need not be de-
- ** clared to equel.
- */
- register char *string;
- int empno;
- char *tl_vector [100];
-
- /*
- ** Another way to do
- ** ## retrieve (name = e.#name, empno =e.number)
- ** ## {
- ** printf("employee #%d is called %s.\n",
- ** empno, name);
- ** ## }
- */
-
- /*
- ** This statement initializes the target list variable.
- ** The '%' sequences indicate the type of the correspond-
- ** ing argument following. Valid types are :
- ** %c -- string of any length
- ** %i2, %i4 -- integer or long
- ** %f4, %f8 -- float or double
- */
-
- string = "%c is e.name, %i2 = e.number";
- tl_vector [0] = name;
- tl_vector [1] = &empno;
-
- ## param retrieve (string, tl_vector)
- ## /*
- ** This statement could also be written
- ** ## param retrieve ("%c is e.name, %i2 = e.number",
- ** ## tl_vector)
- */
- ## {
- printf("employee #%d is called %s.\n", empno, name);
- ## }
-
- /*
- ** Parametrized append, copy, create, define view,
- ** retrieve with a result relation, and replace, may
- ** also be used.
- **
- ** One could say :
- ** ## param append to employee ("name is %c, number is %i2",
- ** ## tl_vector)
- */
- ##}
-
-
-
- /*
- ** This routine reads a string from the terminal and null ter-
- ** minates it. It returns 1 when an eof is read.
- */
-
- eread(p)
- char *p;
- {
- char c;
- while(c = getchar())
- {
- if(c == '\n')
- {
- *p = 0;
- return(0);
- }
- *p++ = c;
- }
- return(1);
- }
-